Design patterns

Jean-Michel Bruel (@jmbruel, jbruel@gmail.com)
version 1.0, 2014-11-18 - First draft

Introduction : importance des patrons

phdComics
–––––––––––––––––– Science is what we understand well enough to explain to a computer. Art is everything else we do. ––––––––––––––––––
Donald Knuth

Point sur le TD de la semaine passée

Principes de conception

Note
Principe de conception

Identifiez les apsects de votre code qui varient et séparez-les de ceux qui demeurent constant.

Principes de conception (suite)

Note
Principe de conception

Programmer une interface, non une implémentation.

Principes de conception (suite)

Note
Principe de conception

Préférez la composition à l’héritage.

Premier patron

Note
Design pattern : Stratégie (Strategy)

Stratégie définit une famille d’algorithmes, encapsule chacun d’eux et les rend interchangeables. Il permet à l’algorithme de varier indépendamment des clients qui l’utilisent.

strategy

Premier exemple d’utilisation de patron

Autre exemple concret

Note Cet exemple est tiré de ce cours.

Le problème

Vous avez une classe FileWriter qui a pour rôle d’écrire dans un fichier ainsi qu’une classe DBWriter. Dans un premier temps, ces classes ne contiennent qu’une méthode write() qui n’écrira que le texte passé en paramètre.

Au fil du temps, vous vous rendez compte que c’est dommage qu’elles ne fassent que ça et vous aimeriez bien qu’elles puissent écrire en différents formats (HTML, XML, etc.) : les classes doivent donc formater puis écrire.

Autre exemple concret (suite)

La solution

Autre exemple concret (suite)

Note
L’interface en PHP (code source ici)
<?php
interface Formater
{
  public function format($text);
}
?>

Autre exemple concret (suite)

Note
La classe abstraite Writer (code source ici)
<?php
abstract class Writer
{
  // Attribut contenant l'instance du formateur que l'on veut utiliser.
  protected $formater;

  abstract public function write($text);

  // Nous voulons une instance d'une classe implémentant Formater en paramètre.
  public function __construct(Formater $formater)
  {
    $this->formater = $formater;
  }
}
?>

Autre exemple concret (suite)

Note
La classe FileWriter (code source ici)
<?php
class FileWriter extends Writer
{
  // Attribut stockant le chemin du fichier.
  protected $file;

  public function __construct(Formater $formater, $file)
  {
    parent::__construct($formater);
    $this->file = $file;
  }

  public function write($text)
  {
    $f = fopen($this->file, 'w');
    fwrite($f, $this->formater->format($text));
    fclose($f);
  }
}
?>

Autre exemple concret (suite)

Note
La classe DBWriter (code source ici)
<?php
class DBWriter extends Writer
{
  protected $db;

  public function __construct(Formater $formater, PDO $db)
  {
    parent::__construct($formater);
    $this->db = $db;
  }

  public function write ($text)
  {
    $q = $this->db->prepare('INSERT INTO lorem_ipsum SET text = :text');
    $q->bindValue(':text', $this->formater->format($text));
    $q->execute();
  }
}
?>

Autre exemple concret (suite)

Enfin, nous avons nos trois formateurs. L’un ne fait rien de particulier (TextFormater), et les deux autres formatent le texte en deux langages différents (HTMLFormater et XMLFormater).

Autre exemple concret (suite)

Note
La classe TextFormater (code source ici)
<?php
class TextFormater implements Formater
{
  public function format($text)
  {
    return 'Date : ' . time() . "\n" . 'Texte : ' . $text;
  }
}
?>

Autre exemple concret (suite)

Note
La classe HTMLFormater (code source ici)
<?php
class HTMLFormater implements Formater
{
  public function format($text)
  {
    return '<p>Date : ' . time() . '<br />' ."\n". 'Texte : ' . $text . '</p>';
  }
}
?>

Autre exemple concret (suite)

Note
La classe XMLFormater (code source ici)
<?php
class XMLFormater implements Formater
{
  public function format($text)
  {
    return '<?xml version="1.0" encoding="ISO-8859-1"?>' ."\n".
           '<message>' ."\n".
           "\t". '<date>' . time() . '</date>' ."\n".
           "\t". '<texte>' . $text . '</texte>' ."\n".
           '</message>';
  }
}
?>

D’autres exemples

  • La fonction standard sort() de python

    >>> sorted("This is a test string from Andrew".split(), key=str.lower)
    ['a', 'Andrew', 'from', 'is', 'string', 'test', 'This']

  • Stratégie de cryptage en fonction de la taille d’un fichier

    File file = getFile();
     Cipher c = CipherFactory.getCipher( file.size() );
     c.performAction();
    
    // implementations:
    interface  Cipher  {
         public void performAction();
    }
    class InMemoryCipherStrategy implements Cipher {
             public void performAction() {
                 // load in byte[] ....
             }
    }
    class SwaptToDiskCipher implements Cipher {
             public void performAction() {
                 // swapt partial results to file.
             }
    }

Tip Plus de détails ici

(non) Réutilisation

Warning Les patrons ne sont pas réutilisables!

Il faut implémeter la solution qu’il représente à chaque fois.

Réutilisation (exception)

Exception : certains font l’objet d’une librairie.

Par exemple le patron Singleton existe dans la bibliothèque standard du langage en Ruby. C’est un mixin qu’il suffit d’inclure dans la classe qui doit être un singleton.

class Klass
   include Singleton
   # ...
end

a,b  = Klass.instance, Klass.instance

a == b
# => true

Klass.new
# => NoMethodError - new is private ...

Un peu d’histoire

1977

Alexander : patterns pour les architectures (les vraies)

1987

Beck et Cunningham : patterns pour des interfaces utilisateurs

1988

Meyer : livre sur l’orienté objet (langage Eiffel), devenu la bible pour beaucoup de programmeurs (cf. [Meyer88])

1990-1995

Gamma, Helm, Johnson et Vlissides : LE livre de référence (cf. [GoF]) NOTE: Les patterns de ce livre sont connus comme les Gof pour « Gang of Four ».

2003

Martin : principes SOLID (cf. [Martin03])

2004

Craig Larman décrit des modèles de conception : les Patterns GRASP (cf. [Larman05])

Exemples de bons principes

SOLID:

  • Single Responsibility Principle
  • Open-Closed Principle
  • Liskov Substitution Principle
  • Interface Segregation Principle
  • Dependency Inversion Principle

Single Responsibility Principle

solid s
Responsabilité => Sujet à changement

Open-Closed Principle

solid o
Ouvert à l'extension mais fermé à la modification

Open-Closed Principle (suite)

Tip Une fois écrite et testée, une classe ne devrait être modifiée que pour être corrigée! Toute modification devrait être possible par extension.

Liskov Substitution Principle

solid l
Une classe doit pouvoir être remplacée par une instance d'un de ses
sous-types, sans modifier la cohérence du programme

LSP : un exemple

Un carré est un rectangle a deux côtés égaux.

carre
Warning Peut-on toujours substituer un Carré à la place d’un Rectangle ?

Interface Segregation Principle

solid i
Préférer plusieurs interfaces spécifiques pour chaque client plutôt qu'une
seule interface générale

Dependency Inversion Principle

solid d
Il faut dépendre des abstractions, pas des implémentations

DIP : explications

Ce principe indique :

  • Les modules de haut niveau (abstraits) ne doivent pas dépendre des modules de bas niveau. Les deux doivent dépendre d’abstractions.
  • Les abstractions ne doivent pas dépendre des détails d’implémentation. C’est l’inverse : les détails doivent dépendre des abstractions.
Note Ainsi ce principe va à l’encontre de l’intuition classique.

SOLID et patrons

Important
QUESTION

Lesquels des 5 principes SOLID s’appliquent bien à Strategy ?

SOLID et patrons (éléments de réponses)

Quelques éléments de réponses :

Single Responsibility Principle

Bof

Open-Closed Principle

Oui : extension (du comportement) sans toucher au code!

Liskov Substitution Principle

Non

Interface Segregation Principle

Oui, mais pas spécifiquement

Dependency Inversion Principle

Oui : les algos dépendent des mêmes abstractions que les données (les interfaces)

GRASP

The critical design tool for software development is a mind well educated in design principles. It is not the UML or any other technology.

Craig Larman, 2005

Il s’agit d’un ensemble de patrons, plutôt orientés conception (UML). Nous en aborderons certains au travers des exemples de ce module (cf. [Larman05]).

Les patrons : comment ça marche ?

Intérêt

  • Réponses éprouvées à des problèmes récurrents
  • Vocabulaire commun

T’as qu’à utiliser une factory!

Warning
QUESTION

Qui fait la nuit de l’info dans un groupe avec des Masters?

Définifion

  • Nom
  • Problème
  • Solution
  • Conséquences

Exemple de Strategy :

Nom

Strategy

Problème

Situations où il est nécessaire de permuter dynamiquement les algorithmes utilisés

Solution

Définir une famille d’algorithmes, encapsuler chacun d’eux en tant qu’objet, et les rendre interchangeables.

Conséquences

Ce patron laisse les algorithmes changer indépendamment des clients qui les emploient.

Patrons à aborder

Patrons à aborder

  • Les "pressentis"

Patrons à aborder

  • Les nouveaux

    • Décorateur
    • Commande
    • Adaptateur
    • Façade
    • Patron de méthode

Patrons à aborder

  • Les "avancés"

    • Chaînes de responsabilité
    • Visiteur

Patrons à aborder

  • Ceux qu’on n’aura pas le temps d’aborder

    • Prototype
    • Mémento
    • Médiateur
    • Interprète
    • Poids-mouche
    • Monteur
    • Pont

Patrons à aborder

  • Concepts avancés

    • Patrons de patrons (exemple du MVC)
    • Anti-patrons

Time for a quizz!

Warning
QUESTION
  • Connectez-vous sur : http://www.socrative.com/ (student login)
  • Ou téléchargez l’application pour étudiant socrative2
  • Choisissez la room 44918d67

Quizz

quizz1

Quizz

quizz2

Quizz

quizz3

Quizz

quizz4

Quizz

quizz5

Quizz

quizz6

Quizz

quizz7

Quizz

quizz8

Quizz

quizz9

Quizz

quizz10

Quizz

quizz11

Quizz

quizz12

Quizz

quizz13

Glossaire et définition

Warning Ces définitions seront enrichies au fur et à mesure des patrons étudiés.

Patrons de création

Singleton

Singleton garantit qu’une classe n’a qu’une seule instance et fournit un point d’accès global à cette instance.

singleton

Patrons comportementaux

Observateur (Observeruk)

Observateur définit une relation entre objets de type un-à-plusieurs, de façon que, lorsqu’un objet change d’état, tous ceux qui en dépendent en soient notifiés et soient mis à jour automatiquement.

Stratégie (Strategyuk)

Stratégie définit une famille d’algorithmes, encapsule chacun d’eux et les rend interchangeables. Il permet à l’algorithme de varier indépendamment des clients qui l’utilisent.

strategy

Références

  • [GoF] Design Patterns: Elements of reusable object oriented software. 1994.
  • [Freeman04] Design Pattren - Head First, O’Reilly, 09/2004.
  • [Cysboy] Apprenez à programmer en Java. Par cysboy. Disponible ici (le 2014-11-18).
  • GOPROD - De bonnes pratiques au service de la conception orientée objets. Disponible ici (le 2014-11-18).
  • [Larman05] Larman, Craig. Applying UML and Patterns – An Introduction to Object-Oriented Analysis and Design and Iterative Development (3rd ed.). Prentice Hall. 2005. ISBN 0-13-148906-2.
  • [Meyer88] Meyer, Bertrand. Object-Oriented Software Construction. Prentice Hall. 1988. ISBN 0-13-629049-3.
  • [Martin03] “Principles Of OOD”, Robert C. Martin (“Uncle BOB”), http://butunclebob.com (Last verified 2014-07-17). Note the reference to “the first five principles”, though the acronym is not used in this article. Dates back to at least 2003.

Conventions d’écriture

Diagrammes UML

Les diagrammes UML™ sont réalisés avec plantUML avec des conventions graphiques propres qui sont listées ci-dessous.

conventions1
Figure 1. Convention http://plantuml.sourceforge.net/[plantUML] pour la visibilité des propriétés/méthodes
conventions
Figure 2. Symboles pour les types de classes

Crédits photos

/